﻿using DXBase;
using DXBase.Structs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DXBase.D2D
{
	/// <summary>
	/// This class provide convenient way to maintain and edit an object transform model 
	/// in a way resilient to numerical error. The final transform is <c>Location * Rotation * Skew * Scale</c>.
	/// </summary>
	public class ModelTransform2D : ModelBase
	{
		public ModelTransform2D()
		{
			SetTransform(new Vector2F(), 0, new Vector2F(), new Vector2F(1, 1));
		}

		public ModelTransform2D Clone()
		{
			var c = new ModelTransform2D();
			c.SetTransform(Location, Rotation, Skew, Scale);
			return c;
		}

		#region Scale

		public Vector2F Scale
		{
			get { return mScale; }
			set
			{
				if (Equals(value, mScale))
					return;
				mScale = value;
				UpdateTransform();
				OnPropertyChanged();
			}
		}
		private Vector2F mScale;

		#endregion

		#region Skew

		public Vector2F Skew
		{
			get { return mSkew; }
			set
			{
				if (Equals(value, mSkew))
					return;
				mSkew = value;
				UpdateTransform();
				OnPropertyChanged();
			}
		}
		private Vector2F mSkew;

		#endregion

		#region Rotation

		public float Rotation
		{
			get { return mRotation; }
			set
			{
				if (Equals(value, mRotation))
					return;
				mRotation = value;
				UpdateTransform();
				OnPropertyChanged();
			}
		}
		private float mRotation;

		#endregion

		#region Location

		public Vector2F Location
		{
			get { return mLocation; }
			set
			{
				if (Equals(value, mLocation))
					return;
				mLocation = value;
				UpdateTransform();
				OnPropertyChanged();
			}
		}
		private Vector2F mLocation;

		#endregion

		#region Transform, SetTransform()

		/// <summary>
		/// The transform Matrix to be used by DirectX
		/// </summary>
		public Matrix3x2F Transform
		{
			get { return mTransform; }
			private set
			{
				if (Equals(value, mTransform))
					return;
				mTransform = value;
				OnPropertyChanged();
			}
		}
		private Matrix3x2F mTransform;

		void UpdateTransform()
		{
			Transform = Matrix3x2F.Translate(Location)
				* Matrix3x2F.Rotation(Rotation)
				* Matrix3x2F.Skew(Skew.X, Skew.Y)
				* Matrix3x2F.Scale(Scale.X, Scale.Y)
				;
		}

		/// <summary>
		/// Set all property in one go and calculate the transform only once.
		/// </summary>
		public void SetTransform(Vector2F position, float rotation, Vector2F skew, Vector2F scale)
		{
			mLocation = position;
			mRotation = rotation;
			mScale = scale;
			mSkew = skew;
			UpdateTransform();
			OnPropertyChanged("Location");
			OnPropertyChanged("Skew");
			OnPropertyChanged("Rotation");
			OnPropertyChanged("Scale");
		}

		#endregion
	}
}
